package cn.tnar.yunpark.careyes.tcp;

import cn.tnar.yunpark.careyes.BCCTool;
import cn.tnar.yunpark.careyes.CarEyesUtil;
import cn.tnar.yunpark.careyes.nbiot.model.NBAckMessage;
import cn.tnar.yunpark.careyes.nbiot.model.NBStatus;
import cn.tnar.yunpark.careyes.tcp.model.AckMessage;
import cn.tnar.yunpark.careyes.tcp.model.HeartBeat;
import cn.tnar.yunpark.careyes.tcp.model.Status;
import cn.tnar.yunpark.careyes.tcp.model.TimeCalibration;
import cn.tnar.yunpark.util.ByteTool;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Calendar;
import java.util.List;


/**
 * author : CaineZhu
 * date   : 2017/12/22
 * desc   : CarEyesTCPMessageDecoder
 */


public class CarEyesTCPMessageDecoder extends ByteToMessageDecoder {

    Logger logger = LoggerFactory.getLogger(this.getClass().getName());

    public int findHeader(ByteBuf buf) {
        int len = buf.readerIndex() + buf.readableBytes();
        int index = -1;
        for (int i = buf.readerIndex(); i < len; i++) {
            byte b = buf.getByte(i);
            if (b == CarEyesUtil.HEADER[0]) {
                int tmp = i + 1;
                if (tmp < len) {
                    byte b1 = buf.getByte(tmp);
                    if (b1 == CarEyesUtil.HEADER[1]) {
                        index = i;
                        break;
                    }
                }
            }
        }
        return index;
    }

    //0x72回复
    public ByteBuf statusResponse(NBStatus record) {
        NBAckMessage ack = new NBAckMessage();
        ack.setLen(0x18);
        ack.setType(0x92);
        return ack.toArray(record.getSensorIdBytes(), record.getParkIdBytes(), record.getCity(), record.getArea(), record.getSequence());
    }

    @Override
    protected void decode(ChannelHandlerContext context, ByteBuf byteBuf, List<Object> list) throws Exception {
        int readable = byteBuf.readableBytes();
        //System.out.println("readable:"+readable);
        if (readable <= 13) {
            return;
        }
        int index = findHeader(byteBuf);
        if (index == -1) {
            return;
        }

        byteBuf.readerIndex(index);//设置游标
        byte type = byteBuf.getByte(2);
        int len = byteBuf.getByte(3) & 0xFF;
        ByteBuf buf = Unpooled.buffer(len);

        try {
            byteBuf.readBytes(buf);
            byte[] data = new byte[buf.readableBytes()];
            buf.getBytes(0, data);
            logger.info("receiver len:{} data:{}", len, ByteTool.bytes2String(data));
            boolean crcValdate = BCCTool.crcValidation(buf);
            if (!crcValdate) {
                logger.warn("crc validation false.");
                return;
            }

            switch (type) {
                case CarEyesUtil.STATUS_TCP: {//上报状态
                    if (len < 31) {
                        return;
                    }
                   // buf.setBytes(0, data);
                    Status record = Status.parse(buf);
                    list.add(record);
                    context.writeAndFlush(Unpooled.copiedBuffer(statusResponse(record)));
                }
                break;
                case CarEyesUtil.HEARTBEAT_ROUTER_TCP: { //网关心跳
                    if (len < 20) {
                        return;
                    }
                    HeartBeat record = HeartBeat.parse(buf);
                    //list.add(record);
                    context.writeAndFlush(Unpooled.copiedBuffer(heartBeatResponse(0x29, record.getRouterId(), record.getSequence())));
                }
                break;
                case CarEyesUtil.HEARTBEAT_DEVICE_TCP: { //设备心跳
                    if (len < 0x14) {
                        return;
                    }
                    HeartBeat record = HeartBeat.parse2(buf);
                    list.add(record);
                    context.writeAndFlush(Unpooled.copiedBuffer(heartBeatResponse(0x50, record.getRouterId(), record.getSequence())));
                }
                break;
                case CarEyesUtil.TIME_CALIBRATION_TCP: { //设备校时
                    if (len < 0x14) {
                        return;
                    }
                    TimeCalibration record = TimeCalibration.parse(buf);
                    //list.add(record);
                    context.writeAndFlush(Unpooled.copiedBuffer(timeResponse(record)));
                }
                break;
                default:
                    //Status record = Status.parse(byteBuf);
                    //list.add(record);
                    byte[] notMatch = "not match".getBytes();
                    context.writeAndFlush(Unpooled.copiedBuffer(notMatch));
            }
        } finally {
            buf.release();
        }

    }

    //状态响应
    public ByteBuf statusResponse(Status st) {
        AckMessage ack = new AckMessage();
        ack.setRouterId(st.getRouterId());
        ack.setSequence(st.getSequence());
        return ack.toArray();
    }

    //网关心跳响应
    public ByteBuf heartBeatResponse(int type, int routerId, int sequence) {
        ByteBuf buf = Unpooled.buffer(0x0E);
        buf.writeByte(0xFF);
        buf.writeByte(0xFE);
        buf.writeByte(type);
        buf.writeByte(0x0E);
        buf.writeByte(routerId);
        buf.writeByte(0x88);
        buf.writeByte(0x02);
        buf.writeByte(0x09);
        buf.writeByte(0x07);
        buf.writeByte(0x00);
        buf.writeByte(sequence);
        buf.writeByte(BCCTool.bccCalc(buf));
        buf.writeByte(0xAB);
        buf.writeByte(0xAA);
        return buf;
    }

    //校时响应
    public ByteBuf timeResponse(TimeCalibration tc) {
        Calendar calendar = Calendar.getInstance();
        ByteBuf buf = Unpooled.buffer(0x14);
        buf.writeByte(0xFF);
        buf.writeByte(0xFE);
        buf.writeByte(0x28);
        buf.writeByte(0x14);
        buf.writeByte(tc.getRouterId());
        buf.writeByte(0x88);
        buf.writeByte(0x02);
        buf.writeByte(0x09);
        buf.writeByte(0x07);
        buf.writeByte(0x00);
        buf.writeByte(CarEyesUtil.int2Bcd(calendar.get(Calendar.YEAR) - 2000));
        buf.writeByte(CarEyesUtil.int2Bcd(calendar.get(Calendar.MONTH) + 1));
        buf.writeByte(CarEyesUtil.int2Bcd(calendar.get(Calendar.DAY_OF_MONTH)));
        buf.writeByte(CarEyesUtil.int2Bcd(calendar.get(Calendar.HOUR_OF_DAY)));
        buf.writeByte(CarEyesUtil.int2Bcd(calendar.get(Calendar.MINUTE)));
        buf.writeByte(CarEyesUtil.int2Bcd(calendar.get(Calendar.SECOND)));
        buf.writeByte(tc.getSequence());
        buf.writeByte(BCCTool.bccCalc(buf));
        buf.writeByte(0xAB);
        buf.writeByte(0xAA);
        return buf;
    }
}
